﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using PureMVC.Interfaces;
using PureMVC.Other;
using System;
using PureMVC.Patterns.Observer;

namespace PureMVC.Core
{
    public partial class View : IView
    {
        public View(string _key)
        {
            if (instanceMap.ContainsKey(_key) && multitionKey != null)
            {
                throw new Exception(MULTITON_MSG);
            }
            multitionKey = _key;
            instanceMap.Add(_key, new WeakLazy<IView>(() => this));
            mediatorMap = new Dictionary<string, IMediator>();
            observerMap = new Dictionary<string, List<IObserver>>();
            InitializeView();
        }

        protected virtual void InitializeView()
        {
        }


        public virtual void RegisterObserver(string _notificationName, IObserver _observer)
        {
            if (observerMap.ContainsKey(_notificationName))
            {
                observerMap[_notificationName].Add(_observer);
            }
            else
            {
                observerMap.Add(_notificationName, new List<IObserver> { _observer });
            }
        }

        public virtual void NotifyObservers(INotification _notification)
        {
            if (!observerMap.ContainsKey(_notification.Name))
            {
                return;
            }
            var list = observerMap[_notification.Name];
            for (int i = 0; i < list.Count; i++)
            {
                list[i].NotifyObserver(_notification);
            }
        }

        public virtual void RemoveObserver(string _notificationName, object _notifyContext)
        {
            if (observerMap.ContainsKey(_notificationName))
            {
                var list = observerMap[_notificationName];
                for (int i = 0; i < list.Count; i++)
                {
                    if (list[i].CompareNotifyContext(_notifyContext))
                    {
                        list.RemoveAt(i);
                        break;
                    }
                }
                if (list.Count == 0)
                {
                    observerMap.Remove(_notificationName);
                }
            }
        }

        public virtual void RegisterMediator(IMediator _mediator)
        {
            if (mediatorMap.ContainsKey(_mediator.MediatorName))
            {
                return;
            }
            mediatorMap.Add(_mediator.MediatorName, _mediator);
            _mediator.InitializeNotifier(multitionKey);
            string[] interests = _mediator.ListNotificationInterests();
            if (interests.Length > 0)
            {
                IObserver observer = new Observer(_mediator.HandleNotification, _mediator);
                for (int i = 0; i < interests.Length; i++)
                {
                    RegisterObserver(interests[i], observer);
                }
            }
            _mediator.OnRegister();
        }

        public virtual IMediator RemoveMediator(string _mediatorName)
        {
            IMediator mediator;
            if (mediatorMap.TryGetValue(_mediatorName, out mediator))
            {
                string[] interests = mediator.ListNotificationInterests();
                for (int i = 0; i < interests.Length; i++)
                {
                    RemoveObserver(interests[i], mediator);
                }
                mediatorMap.Remove(_mediatorName);
                mediator.OnRemove();
            }
            return mediator;
        }

        public virtual bool HasMediator(string _mediatorName)
        {
            return mediatorMap.ContainsKey(_mediatorName);
        }

        public virtual IMediator RetrieveMediator(string _mediatorName)
        {
            IMediator mediator;
            return mediatorMap.TryGetValue(_mediatorName, out mediator) ? mediator : null;
        }

        protected string multitionKey;
        protected Dictionary<string, List<IObserver>> observerMap;
        protected Dictionary<string, IMediator> mediatorMap;
    }
}